package cn.aezo.minions.gen.handler;

import cn.aezo.minions.common.Result;
import cn.aezo.minions.gen.Context;
import cn.aezo.minions.gen.Contextable;
import cn.aezo.minions.gen.render.FtlRender;
import cn.aezo.minions.utils.SmUtils;
import cn.aezo.utils.base.MiscU;
import cn.aezo.utils.base.ValidU;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.FileOutConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import freemarker.template.TemplateException;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author smalle
 * @date 2019-07-31 12:28
 */
@Slf4j
@Data
public class SpringBootHandler extends GenCodeHandler implements Contextable {
    /**
     * model的java包名：entity
     */
    private String baseEntityPackageName = "entity";

    /**
     * dao的java包名：mapper
     */
    private String baseDaoPackageName = "mapper";

    /**
     * 生成maven项目的resources目录：/src/main/resources
     */
    private String mvnMainResourcesDir;

    /**
     * 生成maven项目的java项目基础目录：/src/main/java/cn/aezo/demo
     */
    private String mvnMainJavaProjectBaseDir;

    /**
     * 测试文件目录：/src/test/java/cn/aezo/demo
     */
    private String mvnTestJavaProjectBaseDir;

    /**
     * 权限控制类型：SpringSecurity、OAuth2
     */
    private String addonSecurityType = "SpringSecurity";

    public SpringBootHandler() {
        render = new FtlRender();
    }

    public Result initContext(Context contextParam) {
        Result result = checkTemplateType(contextParam, "SpringBoot");
        if(Result.isError(result)) return result;

        context.setCurrentModule(Context.BackendModule);

        mvnMainJavaProjectBaseDir = "/src/main/java/" + projectConfig.getProjectPackageName().replaceAll("\\.", "\\/");
        mvnMainResourcesDir = "/src/main/resources";
        mvnTestJavaProjectBaseDir = "/src/test/java/" + projectConfig.getProjectPackageName().replaceAll("\\.", "\\/");

        return Result.success();
    }

    @Override
    public Result handleGenCode(Context context) {
        log.info("SpringBootHandler...");

        // initContext(context);
        try {
            doGen();
        } catch (IOException | TemplateException e) {
            e.printStackTrace();
            return Result.failure("生成SpringBoot代码出错");
        }

        return Result.success();
    }

    @Override
    public Map<String, Object> getContextMap() {
        // 渲染模板参数
        Map<String, Object> dataMap = MiscU.Instance.toMap(
                "baseEntityPackagePath", projectConfig.getProjectPackageName() + "." + baseEntityPackageName,
                "baseDaoPackagePath", projectConfig.getProjectPackageName() + "." + baseDaoPackageName,
                "mvnMainJavaProjectBaseDir", this.mvnMainJavaProjectBaseDir,
                "mvnMainResourcesDir", this.mvnMainResourcesDir,
                "mvnTestJavaProjectBaseDir", this.mvnTestJavaProjectBaseDir);
        dataMap.put("baseApplicationName", SmUtils.toUpperCaseFirst(projectConfig.getProjectName()));
        dataMap.put("addonSecurityType", this.addonSecurityType);
        dataMap.put("renderNotRender", FtlRender.NotRender);
        return MiscU.Instance.toMap("sbhCtx", dataMap);
    }

    protected void doGen() throws IOException, TemplateException {
        super.doGen();

        // 生成Mybatis：model、mapper、dao
        initModelMapperAndDaoByMybatis();
    }

    /**
     * 生成Mybatis：model、mapper、dao
     */
    private void initModelMapperAndDaoByMybatis() {
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = getProjectModuleDirAbs();
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("minions");
        gc.setOpen(false);
        gc.setIdType(IdType.ID_WORKER_STR);
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl(projectConfig.getDatabaseUrl());
        dsc.setDriverName(projectConfig.getDatabaseDriver());
        dsc.setUsername(projectConfig.getDatabaseUsername());
        dsc.setPassword(projectConfig.getDatabasePassword());
        mpg.setDataSource(dsc);

        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setParent(projectConfig.getProjectPackageName());
        pc.setMapper(baseDaoPackageName);
        mpg.setPackageInfo(pc);

        // 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };

        // 如果模板引擎是 freemarker
        String templatePath = "/templates/mapper.xml.ftl";

        // 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定义配置会被优先输出
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(com.baomidou.mybatisplus.generator.config.po.TableInfo tableInfo) {
                // 自定义输出文件名
                String daoPath = projectPath + "/src/main/resources/"+ baseDaoPackageName;
                String mapperFile = "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
                return ValidU.isEmpty(pc.getModuleName()) ? (daoPath + mapperFile) : (daoPath + "/" + mapperFile);
            }
        });

        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);

        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();
        // 配置自定义输出模板
        // templateConfig.setEntity();
        // templateConfig.setService();
        // templateConfig.setController("");

        templateConfig.setXml(null);
        mpg.setTemplate(templateConfig);

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setTablePrefix("sys_"); // 此处可以修改表前缀
        strategy.setNaming(NamingStrategy.underline_to_camel); // 表名生成策略
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        strategy.setControllerMappingHyphenStyle(true);
        List<String> tables = context.getDs().getTableInfo().getSearchTableNames();
        if(ValidU.isNotEmpty(tables)) {
            strategy.setInclude(tables.toArray(new String[]{}));
        }
        strategy.setVersionFieldName("version");
        strategy.setLogicDeleteFieldName("valid_status");

        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
    }
}
